# coding=utf-8
#*****************************************************************************
#       Copyright (C) 2008 Arnaud bergeron <abergeron@gmail.com>
#
#  Distributed under the terms of the GNU General Public License version 2 (GPLv2)
#
#  The full text of the GPLv2 is available at:
#
#                  http://www.gnu.org/licenses/
#*****************************************************************************

from sage.words.words import Words
from sage.words.word import FiniteWord
from sage.words.alpha import Alphabet
from sage.plot.plot import arrow, line, polygon, point, Graphics
from sage.plot.axes import GridLines
from sage.modules.free_module_element import vector
from sage.rings.integer import Integer
from utils import last_it

def Paths(alpha = 'aAbB'):
    r"""
    Returns the set of paths.
    
    INPUT:
        alpha -- (alphabet, default: 'aAbB'), the alpahbet over which the
                 paths will be defined.  The order is East, West, North, South.
                 It must have a length of 4.
    EXAMPLES:
    The default version:
        sage: Paths()
        Paths over ['a', 'A', 'b', 'B']
        
    If you don't like the default alphabet you can provide your own:
        sage: Paths('EWNS')
        Paths over ['E', 'W', 'N', 'S']
        
    But it must be exactly 4 symbols in length:
        sage: Paths('ab')
        Traceback (most recent call last):
        ...
        ValueError: the alphabet must have four symbols
        sage: Paths([0, 1, 2, 3, 4, 5])
        Traceback (most recent call last):
        ...
        ValueError: the alphabet must have four symbols
    """
    alpha = Alphabet(alpha)
    if len(alpha) != 4:
        raise ValueError, "the alphabet must have four symbols"
    res = Words(alpha, infinite=False, fclass=WordPath)
    res.rename("Paths over %s"%alpha.string_rep())
    return res

class WordPath(FiniteWord):
    def _repr_(self):
        r"""
        Returns a string representation of this path.
        
        EXAMPLES:
            sage: P = Paths()
            sage: P('abAB')
            Path: abAB
            sage: P('abbabaab')
            Path: abbabaab
        """
        return "Path: %s"%self.string_rep()
    
    def plot(self, polygon=False, pathoptions=dict(rgbcolor='red'), 
             startpoint=False, startoptions=dict(rgbcolor='green'), 
             endpoint=False, endoptions=dict(rgbcolor='green'), 
             showgrid=False, gridoptions=dict()):
        r"""
        INPUT:
            pathoptions -- (dict, default: {'rgbcolor': 'red'}), options
                           for the path drawing
            polygon -- (boolean, default: False), draw as a polygon if
                       the path is closed
            startpoint -- (boolean, default: False), draw the start point?
            startoptions -- (dict, default: {'rgbcolor': 'green'}) options
                            for the start point drawing
            endpoint -- (boolean, default: False), draw the end point?
            endoptions -- (dict, default: {'rgbcolor': 'green'}) options
                          for the end point drawing
            showgrid -- (boolean, default: True), show grid?
            gridoptions -- (dict, default: {}), options for the grid drawing
        """
        G = Graphics()
        pts = tuple(self.points())
        if startpoint:
            G += point(pts[0], **startoptions)
        if endpoint:
            G += point(pts[-1], **endoptions)
        if polygon and self.is_closed():
            G += polygon(pts, **pathoptions)
        else:
            G += line(pts, **pathoptions)
        if showgrid:
            pass # no way to do this (yet)
            #G.gridlines(True)
        G.axes(False)
        G.set_aspect_ratio(1)
        return G
    
    def points(self):
        r"""
        Returns an iterator yielding a list of points used to draw the path 
        represented by this word.
        
        The walks along the path are one unit in length for each direction.
        
        EXAMPLES:
        A simple closed square
            sage: P = Paths()
            sage: list(P('abAB').points())
            [(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]
           
        A sligthly more complicated figure 
            sage: list(P('abaB').points())
            [(0, 0), (1, 0), (1, 1), (2, 1), (2, 0)]
        """
        directions = (vector((Integer(1), Integer(0))), vector((Integer(-1), Integer(0))),\
                      vector((Integer(0), Integer(1))), vector((Integer(0), Integer(-1))))
        curpt = vector((Integer(0), Integer(0)))
        yield curpt
        for l in self._content:
            curpt += directions[l]
            yield curpt
    
    def directive_vector(self, options=dict(rgbcolor='blue')):
        r"""
        Returns an arrow graphics that goes from the start of the word 
        to the end.
        
        INPUT:
            options -- (dictionary, default: {'rgbcolor': 'blue'} graphic 
                       options for the arrow
        """
        pts = self.points()
        start = pts.next()
        end = last_it(pts)
        if (start == end) :
            return point(start, pointsize=10, **options)
        return arrow(start, end, **options)
    
    def is_closed(self):
        r"""
        Returns True if self represents a closed path and False otherwise.
        
        EXAMPLES:
            sage: P = Paths()
            sage: P('aA').is_closed()
            True
            sage: P('abAB').is_closed()
            True
            sage: P('ababAABB').is_closed()
            True
            sage: P('aaabbbAABB').is_closed()
            False
        """
        tab = self.parikh_vector()
        return tab[0] == tab[1] and tab[2] == tab[3]
